<?php
declare (strict_types = 1);

namespace app\command;

use think\console\Command;
use think\console\Input;
use think\console\input\Argument;
use think\console\input\Option;
use think\console\Output;
use think\facade\Db;
use app\service\TopviewApiService;
use app\service\OssService;

class M2vTaskStatus extends Command
{
    protected $apiService;
    protected $ossService;

    protected function configure()
    {
        $this->setName('m2v:status')
            ->setDescription('拉取M2V任务执行状态')
            ->addOption('limit', null, Option::VALUE_OPTIONAL, '每次处理的任务数量', 100)
            ->addOption('sleep', null, Option::VALUE_OPTIONAL, '每次处理完后休眠的秒数', 5);
    }

    protected function execute(Input $input, Output $output)
    {
        $this->apiService = new TopviewApiService();
        $this->ossService = new OssService();
        $limit = $input->getOption('limit');
        $sleep = $input->getOption('sleep');

        while (true) {
            try {
                $this->processUnfinishedTasks($limit, $output);
                $output->writeln(date('Y-m-d H:i:s') . ' - 休眠 ' . $sleep . ' 秒');
                sleep($sleep);
            } catch (\Exception $e) {
                $output->writeln(date('Y-m-d H:i:s') . ' - 错误: ' . $e->getMessage());
                sleep($sleep);
            }
        }
    }

    /**
     * 处理未完成的任务
     * @param int $limit 每次处理的任务数量
     * @param Output $output 输出对象
     */
    protected function processUnfinishedTasks($limit, Output $output)
    {
        // 获取未完成的任务
        $tasks = Db::name('m2v_tasks')
            ->where('status', 'in', [0, 1]) // 待处理或处理中的任务
            ->limit($limit)
            ->select();
        if ($tasks->isEmpty()) {
            $output->writeln(date('Y-m-d H:i:s') . ' - 没有需要更新的任务');
            return;
        }

        $output->writeln(date('Y-m-d H:i:s') . ' - 开始处理 ' . count($tasks) . ' 个任务');

        foreach ($tasks as $task) {
            try {
                // 查询远程任务状态
                $result = $this->apiService->queryM2vTask($task['task_id']);
                // 更新任务状态
                $newStatus = $this->convertStatus($result['status']);
                $updateData = [
                    'status' => $newStatus,
                    'update_time' => date('Y-m-d H:i:s')
                ];

                // 如果任务完成，下载视频并上传到OSS
                if ($result['status'] === 'completed' || $result['status'] === 'success') {
                    $originalVideoUrl = $result['exportVideos'][0]['videoUrl'] ?? '';
                    if ($originalVideoUrl) {
                        try {
                            // 将视频上传到OSS
                            $ossVideoUrl = $this->uploadVideoToOss($originalVideoUrl, $task['task_id']);
                            $updateData['video_url'] = $ossVideoUrl;
                            $output->writeln("任务 {$task['task_id']} 已完成，OSS视频地址：{$ossVideoUrl}");
                        } catch (\Exception $e) {
                            // 如果OSS上传失败，仍然保存原始URL
                            $updateData['video_url'] = $originalVideoUrl;
                            $output->writeln("任务 {$task['task_id']} OSS上传失败，保存原始URL：{$originalVideoUrl}，错误：" . $e->getMessage());
                        }
                    } else {
                        $output->writeln("任务 {$task['task_id']} 已完成但没有获取到视频URL");
                    }
                }

                // 如果任务失败，保存错误信息并返还积分
                if ($result['status'] === 'failed') {
                    $updateData['error_msg'] = $result['errorMsg'] ?? '生成失败';
                    $output->writeln("任务 {$task['task_id']} 失败：{$updateData['error_msg']}");
                    
                    // 返还用户积分
                    try {
                        if ($task['points'] > 0) {
                            $pointsService = new \app\service\PointsService();
                            $pointsService->recharge(
                                $task['user_id'], 
                                $task['points_consumed'],
                                '',
                                "图片转视频任务{$task['task_id']}失败退还积分"
                            );
                            $output->writeln("任务 {$task['task_id']} 失败，已退还{$task['points']}积分");
                        }
                    } catch (\Exception $e) {
                        $output->writeln("任务 {$task['task_id']} 失败且积分退还失败: " . $e->getMessage());
                    }
                }

                // 更新数据库
                $affectedRows = Db::name('m2v_tasks')
                    ->where('id', $task['id'])
                    ->update($updateData);

                $output->writeln("任务 {$task['task_id']} 状态更新为：{$result['status']} -> {$newStatus} (影响行数: {$affectedRows})");

            } catch (\Exception $e) {
                $output->writeln("任务 {$task['task_id']} 更新失败：" . $e->getMessage());
                continue;
            }
        }
    }

    /**
     * 将视频上传到OSS
     * @param string $videoUrl 远程视频URL
     * @param string $taskId 任务ID
     * @return string OSS视频URL
     * @throws \Exception
     */
    private function uploadVideoToOss($videoUrl, $taskId)
    {
        // 检查是否已经是OSS地址
        if (strpos($videoUrl, 'bd-robot.oss-cn-beijing.aliyuncs.com') !== false) {
            return $videoUrl; // 已经是OSS地址，直接返回
        }
        var_dump($videoUrl);
        // 下载视频文件
        $tempFile = $this->downloadVideo($videoUrl, $taskId);
        var_dump($tempFile);
        try {
            // 生成OSS路径
            $extension = pathinfo(parse_url($videoUrl, PHP_URL_PATH), PATHINFO_EXTENSION);
            if (empty($extension)) {
                $extension = 'mp4'; // 默认扩展名
            }
            $ossPath = "m2v/{$taskId}/output." . $extension;
            
            // 上传到OSS
            $ossUrl = $this->ossService->putObject($ossPath, $tempFile);
            
            // 删除临时文件
            if (file_exists($tempFile)) {
                unlink($tempFile);
            }
            
            return $ossUrl;
        } catch (\Exception $e) {
            // 删除临时文件
            if (file_exists($tempFile)) {
                unlink($tempFile);
            }
            throw $e;
        }
    }

    /**
     * 下载视频文件到本地临时目录
     * @param string $videoUrl 视频URL
     * @param string $taskId 任务ID
     * @return string 本地临时文件路径
     * @throws \Exception
     */
    private function downloadVideo($videoUrl, $taskId)
    {
        // 创建临时目录
        $tempDir = sys_get_temp_dir() . '/m2v_videos';
        if (!is_dir($tempDir)) {
            mkdir($tempDir, 0755, true);
        }
        
        // 生成临时文件名
        $extension = pathinfo(parse_url($videoUrl, PHP_URL_PATH), PATHINFO_EXTENSION);
        if (empty($extension)) {
            $extension = 'mp4';
        }
        $tempFile = $tempDir . '/' . $taskId . '_' . time() . '.' . $extension;
        
        // 下载文件
        $context = stream_context_create([
            'http' => [
                'timeout' => 300, // 5分钟超时
                'user_agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
            ]
        ]);
        
        $videoContent = file_get_contents($videoUrl, false, $context);
        if ($videoContent === false) {
            throw new \Exception("下载视频失败：{$videoUrl}");
        }
        
        if (file_put_contents($tempFile, $videoContent) === false) {
            throw new \Exception("保存临时文件失败：{$tempFile}");
        }
        
        return $tempFile;
    }

    /**
     * 转换状态
     * @param string $status 远程任务状态
     * @return int
     */
    private function convertStatus($status)
    {
        $statusMap = [
            'pending' => 0,    // 待处理
            'processing' => 1, // 处理中
            'completed' => 2,  // 已完成
            'success' => 2,    // 已完成（成功）
            'failed' => 3      // 失败
        ];
        return $statusMap[$status] ?? 0;
    }
} 